/* eslint-disable @typescript-eslint/no-explicit-any */
/*—————————————————————————————————————————————————————————— table公共组件 ——————————————————————————————————————————————————————————*/
/*
*传入参数
  style?: tabla组件外层额外style
  className?: tabla组件外层额外css
  bordered?:是否展示外边框和列边框,默认false	
  isDrag?:是否开启拖拽,默认false
  itemUniqueIdentification ?: 成员唯一标识选取字段名称,默认id
  head: 表格头部数组
  scrollToFirstRowOnChange?:当分页、排序、筛选变化后是否滚动到表格顶部，默认true
  scrollX?:  设置横向滚动，也可用于指定滚动区域的宽，可以设置为像素值，百分比，true 和 'max-content',默认 100%
  scrollY?: 设置纵向滚动，也可用于指定滚动区域的高，可以设置为像素值
  rowChangeType?:  多选，单选，或者不需要选择,默认 none
  selectedList?: 开启多选或单选后，需要默认选中的成员列表

  分页器配置
  pagination?: {
      type: ['showTotal', 'showQuickJumper', 'showSizeChanger'], // 分页器展示类型,默认全部展示
      postion: 'Center', // 分页器展示位置,默认Center
      pageSizeOptions: [10, 20, 30] // 指定每页可以显示多少条,默认10 20 30
    }
  paginationShow?: // 是否展示分页器,默认true
  paginationDisabled?:  是否禁用分页器，默认false
  api?:  接口请求地址
  apiQuery?: 接口请求额外参数

*交互方法
  expandedRowRender?: 额外的展开行配置方法(即怎么渲染展开区域成员),参考antd官网使用

  rowExpandable?: 设置是否允许行展开(即过滤是否要展开的成员内容),参考antd官网使用

  rowSelectionChange?:单选或多选时，成员选择回调函数,参数 newSelectedRowKeys 当前选中的成员key列表 ； selected 当前选中的成员列表

  paginationChange?: 分页器组件内容发生改变方法,参数 page 当前页码 ； size 当前页面展示条数

  dragChange?:成员拖拽改变函数,参数 changList 改变后的成员列表 ；prev 改变前的成员列表 ； activeIndex 改变前的位置信息 ； overIndex 改变后位置信息

***用法介绍***
  1.进行成员head数组配置时，可参考:https://ant-design.antgroup.com/components/table-cn#column
  2.本组件ref抛出属性，可以参考 TableRef 接口，此接口已经导出，可以按需要酌情使用
  3.如无特殊要求，只需传入请求地址+请求内容即可，此组件会根据接口情况进行操作，包括页面变化等
*/
// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

// 数据+css引入
import React, {
  useEffect,
  useState,
  forwardRef,
  useImperativeHandle,
  useMemo,
} from 'react'

// ts接口
// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
import type {
  TablesProps,
  ColumnsType,
  PaginationProps,
  TableRef,
  SelectionChange,
  RowProps,
} from './interface'

// 组件引入
// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
import { Table } from 'antd' // table组件引入

// 拖拽组件引入
import type { DragEndEvent } from '@dnd-kit/core'
import { DndContext, PointerSensor, useSensor, useSensors } from '@dnd-kit/core'
import { restrictToVerticalAxis } from '@dnd-kit/modifiers'
import {
  SortableContext,
  arrayMove,
  useSortable,
  verticalListSortingStrategy,
} from '@dnd-kit/sortable'
import { CSS } from '@dnd-kit/utilities'

// 拖拽成员组件
// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
const Row = (props: RowProps) => {
  const {
    attributes,
    listeners,
    setNodeRef,
    transform,
    transition,
    isDragging,
  } = useSortable({
    id: props['data-row-key'],
  })

  const style: React.CSSProperties = {
    ...props.style,
    transform: CSS.Transform.toString(transform && { ...transform, scaleY: 1 }),
    transition,
    cursor: 'move',
    ...(isDragging ? { position: 'relative', zIndex: 9999 } : {}),
  }

  return (
    <tr
      {...props}
      ref={setNodeRef}
      style={style}
      {...attributes}
      {...listeners}
    />
  )
}

// 页面书写区
// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
const Tables = forwardRef(
  (props: TablesProps, ref: React.ForwardedRef<TableRef>) => {
    // 参数结构
    const {
      style, // tabla组件外层额外style
      className, // tabla组件外层额外css
      bordered = false, // 是否展示外边框和列边框,默认false
      isDrag = false, // 是否开启拖拽,默认false
      itemUniqueIdentification = 'id', // 成员唯一标识选取字段名称,默认id
      head = [], // 表格头部数组
      scrollToFirstRowOnChange = true, // 当分页、排序、筛选变化后是否滚动到表格顶部，默认true
      scrollX: x = '100%', // 设置横向滚动，也可用于指定滚动区域的宽，可以设置为像素值，百分比，true 和 'max-content',默认 100%
      scrollY: y = '', // 设置纵向滚动，也可用于指定滚动区域的高，可以设置为像素值
      rowChangeType = 'none', // 多选，单选，或者不需要选择,默认 none
      selectedList = [], // 开启多选或单选后，需要默认选中的成员列表
      paginationShow = true, // 是否展示分页器,默认true
      paginationDisabled = false, // 是否禁用分页器，默认false
      // 分页器配置
      pagination = {
        type: ['showTotal', 'showQuickJumper', 'showSizeChanger'],
        postion: 'Center',
        pageSizeOptions: [10, 20, 30],
      },
      api, // 接口请求地址
      apiQuery = null, // 接口请求额外参数

      // 方法区域
      // -----------------------------------------------------------------------------------------------------------
      expandedRowRender, // 额外的展开行配置方法(即怎么渲染展开区域成员)
      rowExpandable, // 设置是否允许行展开(即过滤是否要展开的成员内容)
      rowSelectionChange, // 单选或多选时，成员选择回调函数

      // 分页器组件内容发生改变方法
      paginationChange,

      // 成员拖拽改变函数
      dragChange,
    } = props

    // 变量声明区
    // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
    // 状态声明
    // -----------------------------------------------------------------------------------------------------------
    const [data, setData] = useState<Array<unknown>>([]) // 表格数据
    const [selectedRowKeys, setSelectedRowKeys] =
      useState<React.Key[]>(selectedList) // 多选或单选内容
    const [loading, setLoading] = useState<boolean>(false) // 展示loading开关

    // 分页器
    // =================================================================================
    const [total, setTotal] = useState<number>(0) // 分页器总数
    const [current, setCurrent] = useState<number>(1) // 当前页数
    const [pageSize, setPageSize] = useState<number>(10) // 每页条数

    // 函数使用区
    // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
    // memo数据

    // 计算总页数，只有当总页数和每页条数变化时，才会重新计算
    const PageCount = useMemo(
      () => Math.ceil(total / pageSize),
      [total, pageSize]
    )

    // 暴露给父组件的方法
    // -----------------------------------------------------------------------------------------------------------
    useImperativeHandle(ref, () => ({
      data, // 内容数组
      // 修改当前内容数组
      modifyData(newData) {
        setLoading(true)
        setData(newData)
        setLoading(false)
      },

      selectedRowKeys, // 当前选中内容组合数组
      // 修改选择内容数组
      modifySelectedRowKeys(newSelected) {
        setSelectedRowKeys(newSelected)
      },

      loading, // 当前是否在加载内容
      // 修改loading状态
      modifyLoading(state) {
        setLoading(state)
      },

      // 分页器部分
      // =================================================================================
      total, // 总条数
      PageCount, // 总页数

      current, // 当前页数
      modifyCurrent(newCurrent) {
        setCurrent(newCurrent)
      },

      pageSize, // 每页条数
      // 修改当前每页条数
      currentPageSize(newPageSize) {
        setPageSize(newPageSize)
      },

      // 中立方法
      // =================================================================================
      // 表格刷新函数
      refresh() {
        apiRequest()
      },
    }))

    // hook函数
    // -----------------------------------------------------------------------------------------------------------
    // 监听 接口额外参数 或 刷新开关的变化
    useEffect(() => {
      // 如果变化了则重置到第一页
      apiQuery && setCurrent(1)
    }, [JSON.stringify(apiQuery)])

    // 监听 接口地址 或 当前页数 或者 当前页面数变化时
    // =================================================================================
    useEffect(() => {
      // 进行接口请求
      apiQuery && apiRequest()
    }, [api, current, pageSize])

    // 事件函数
    // -----------------------------------------------------------------------------------------------------------
    // 接口请求函数
    const apiRequest = () => {
      // 开启loading
      setLoading(true)

      // 模拟接口
      return new Promise((resolve) => {
        setTimeout(() => {
          resolve({
            total: 11,
            list: [],
          })
        }, 1000)
      })
        .then((res: any) => {
          setTotal(res.total)
          setData(res.list)
        })
        .finally(() => {
          setLoading(false)
        })
    }

    // 单选或多选
    // =================================================================================
    // 项目筛选变化时
    const selectionChange: SelectionChange = (newSelectedRowKeys, selected) => {
      setSelectedRowKeys(newSelectedRowKeys as React.Key[])
      rowSelectionChange && rowSelectionChange(newSelectedRowKeys, selected)
    }

    // 分页器
    // =================================================================================
    // 当前页数发生变化
    const currentChange: PaginationProps['onChange'] = (page, size) => {
      // 改变当前页数
      setCurrent(page)

      // 使用 父级传入函数
      paginationChange && paginationChange(page, size)
    }

    // 当前页面展示条数发生变化
    const pageSizeChange: PaginationProps['onShowSizeChange'] = (
      page,
      size
    ) => {
      // 改变当前选中的页面大小值
      setPageSize(size)

      // 使用 父级传入函数
      paginationChange && paginationChange(page, size)
    }

    // 拖拽组件配置方法
    // =================================================================================
    // 执行拖拽内容初始化参数
    const sensors = useSensors(
      useSensor(PointerSensor, {
        activationConstraint: {
          // https://docs.dndkit.com/api-documentation/sensors/pointer#activation-constraints
          distance: 1,
        },
      })
    )

    // 拖拽成员发生改变时
    const onDragEnd = ({ active, over }: DragEndEvent) => {
      if (active.id !== over?.id) {
        // 改变当前的渲染数组
        setData((prev) => {
          // 改变前的位置信息
          const activeIndex = prev.findIndex(
            (i) => i[itemUniqueIdentification] === active.id
          )
          // 改变后的位置信息
          const overIndex = prev.findIndex(
            (i) => i[itemUniqueIdentification] === over?.id
          )
          // 改变后的成员组合
          const changList = arrayMove(prev, activeIndex, overIndex)

          // 拖拽成员改变回调
          dragChange && dragChange(changList, prev, activeIndex, overIndex)
          return changList
        })
      }
    }

    // dom元素区域
    // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
    return (
      // 拖拽组件使用
      <DndContext
        sensors={sensors}
        modifiers={[restrictToVerticalAxis]}
        onDragEnd={onDragEnd}
      >
        <SortableContext
          // rowKey array
          items={data.map((i) => i[itemUniqueIdentification])}
          strategy={verticalListSortingStrategy}
        >
          {/* 表格组件使用 */}
          <Table
            // tabla组件外层额外style
            style={style}
            // tabla组件外层额外css
            className={className}
            // 表格边框
            bordered={bordered}
            // 表格行 key 的取值
            rowKey={itemUniqueIdentification}
            // 绑定头部
            columns={head}
            // 表格大小
            size="large"
            // 真实内容数据
            dataSource={data}
            // 表格出现滑动宽高设置
            scroll={{ scrollToFirstRowOnChange, x, y }}
            // 拖拽组件使用时触发，替换表格成员为拖拽所需成员
            // -------------------------------------------------------------------------------------------
            components={{
              body: {
                row: isDrag && Row,
              },
            }}
            // loading展示内容
            // -------------------------------------------------------------------------------------------
            loading={{
              tip: '加载中...', // loading时展示内容
              spinning: loading, // loading开关
            }}
            // 单选或多选内容配置
            // -------------------------------------------------------------------------------------------
            rowSelection={
              // 只有当需要单选或多选时才能生效配置
              rowChangeType !== 'none' && {
                type: rowChangeType, // 单选 | 多选
                selectedRowKeys, // 当前选中内容组合数组
                selections: rowChangeType !== 'radio' && [
                  Table.SELECTION_INVERT,
                  Table.SELECTION_NONE,
                ], // 当为多选时才能进行筛选
                onChange: selectionChange, // 选择改变触发函数
              }
            }
            // 展开列的属性配置
            // -------------------------------------------------------------------------------------------
            expandable={{
              fixed: 'left', // 固定在最左边
              expandedRowRender, // 额外的展开行配置方法(即怎么渲染展开区域成员)
              rowExpandable, // 设置是否允许行展开(即过滤是否要展开的成员内容)
            }}
            // 分页器内容的绑定
            // -------------------------------------------------------------------------------------------
            pagination={
              // 只有当开启分页器开关 并且 此时有数据时，才能进行分页器配置
              paginationShow &&
              data.length && {
                position: [`bottom${pagination.postion}`], // 分页器固定在下方，具体位置可自定义
                total, // 总条数
                current, // 当前页数
                pageSize, // 每页条数
                disabled: paginationDisabled, // 是否禁用分页器
                pageSizeOptions: pagination.pageSizeOptions, // 指定每页可以显示多少条
                showQuickJumper: pagination.type.includes('showQuickJumper'), // 是否展示页面跳转组件
                showSizeChanger: pagination.type.includes('showSizeChanger'), // 是否展示每页显示条目数组件
                showTotal: (totals) =>
                  pagination.type.includes('showTotal')
                    ? `共 ${totals} 条`
                    : '', // 是否展示总条数
                onChange: currentChange, // 页码或 pageSize 改变的回调，参数是改变后的页码及每页条数
                onShowSizeChange: pageSizeChange, // 页面展示最大数 变化的回调
              }
            }
          />
        </SortableContext>
      </DndContext>
    )
  }
)

export type { ColumnsType, TableRef }

export default Tables
